package org.elec.mac.controller;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.elec.mac.ehcache.CacheConfiguration;
import org.elec.mac.ehcache.ManageEhCache;
import org.elec.mac.entity.OAuthToken;
import org.elec.mac.utils.Utils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Controller
public class WxController {

    @Autowired
    private ManageEhCache manageEhCache;

    @Autowired
    private CacheConfiguration cacheConfiguration;

    @Value("${tencent.wx.api}")
    private String url;

    @Value("${tencent.wx.tokenurl}")
    private String tokenurl;

    @Value("${tencent.wx.jsapiurl}")
    private String jsapiurl;

    @Value("${tencent.wx.userinfourl}")
    private String userinfourl;

    @Value("${tencent.wx.appid}")
    private String appid;

    @Value("${tencent.wx.secret}")
    private String secret;

    @Value("${access.token.url}")
    private String accessTokenUrl;

    @Value("${tencent.wxpay.paypage}")
    private String payPageUrl;

    private String openid;
    // 系统鉴权信息
    private String accesstoken;
    // 微信鉴权信息
    private String access_token;

    @RequestMapping(value = "/weixin.do")
    private String weixinHandler(HttpServletRequest request, HttpServletResponse response, ModelMap model) throws IOException {
        EhCacheCacheManager manager
                = cacheConfiguration.ehCacheCacheManager(cacheConfiguration.ehCacheManagerFactoryBean());
        String code = request.getParameter("code");
        String state = request.getParameter("state");
        String user_agent = request.getHeader("User-Agent");
        accesstoken = request.getParameter("accesstoken");
        openid = request.getParameter("openid");
        // 用户微信鉴权获取用户微信信息
        if(StringUtils.isNotBlank(code)) {
            OAuthToken authToken = new OAuthToken();
            OkHttpClient httpClient = new OkHttpClient();
            RequestBody body = new FormBody.Builder().add("appid", appid)
                    .add("secret", secret)
                    .add("code", code)
                    .add("grant_type", "authorization_code").build();
            Request req = new Request.Builder().url(url).post(body).build();
            Response resp = httpClient.newCall(req).execute();
            if(resp.isSuccessful()) {
                JSONObject responseBody = new JSONObject(resp.body().string());
                log.info(responseBody.toString());
                try {
                    int errcode = responseBody.getInt("errcode");
                    response.sendRedirect("/index.do?mach=1");
                    return null;
                } catch(Exception ex) {
                }
                try {
                    // 获取鉴权信息
                    openid = (String) responseBody.get("openid");
                    access_token = (String) responseBody.get("access_token");
                    authToken.setAccess_token(access_token);
                    authToken.setExpires_in(responseBody.get("expires_in").toString());
                    authToken.setLogin_time(System.currentTimeMillis());
                    authToken.setOpenid(openid);
                    authToken.setRefresh_token(responseBody.get("refresh_token").toString());
                    authToken.setScope((String) responseBody.get("scope"));
                } catch(Exception ex) {
                    log.error("获取微信鉴权异常", ex);
                    response.sendRedirect("/network.html");
                    return null;
                }
                // 获取用户信息
                body = new FormBody.Builder().add("access_token", access_token)
                        .add("openid", openid)
                        .add("lang", "zh_CN").build();
                req = new Request.Builder().url(userinfourl).post(body).build();
                resp = httpClient.newCall(req).execute();
                if(resp.isSuccessful()) {
                    JSONObject responseBody2 = new JSONObject(resp.body().string());
                    accesstoken = getAccessToken(responseBody2, user_agent);
                    if(StringUtils.isBlank(accesstoken)) {
                        response.sendRedirect("/network.html");
                        return null;
                    }
                } else {
                    log.error("获取用户信息失败");
                    response.sendRedirect("/network.html");
                    return null;
                }
            } else {
                log.error("获取鉴权信息失败");
                response.sendRedirect("/network.html");
                return null;
            }
            Cache authTokenCache = manager.getCache("authTokenCache");
            authTokenCache.put(openid, authToken);
        }
        if(StringUtils.isBlank(openid)) {
            response.sendRedirect("/index.do?mach=" + state);
            return null;
        }
        model.put("mach", state);
        model.put("openid", openid);
        model.put("appid", appid);
        model.put("accesstoken", accesstoken);
        return "main";
    }

    @RequestMapping(value = "/paypage.do")
    private String payPageHandler(HttpServletRequest request, HttpServletResponse response, ModelMap model) throws IOException {
        String openid = request.getParameter("openid");
        String accesstoken = request.getParameter("accesstoken");
        String mach = request.getParameter("mach");

        Map<String, String> mapSign = Utils.wxConfigMap(payPageUrl);

        model.put("accesstoken", accesstoken);
        model.put("mach", mach);
        model.put("openid", openid);
        model.put("appid", appid);
        model.put("noncestr", mapSign.get("noncestr"));
        model.put("timestamp", mapSign.get("timestamp"));
        model.put("signature", mapSign.get("sign"));

        return "paypage";
    }

    /**
     * @param json
     * @param user_agent
     * @return
     * @throws IOException
     */
    private String getAccessToken(JSONObject json, String user_agent) throws IOException {
        JSONObject responseBody;
        JSONObject requestJson = new JSONObject();
        OkHttpClient httpClient = new OkHttpClient();
        MediaType JSON = MediaType.parse("application/json;charset=utf-8");
        requestJson.put("reg", user_agent);
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map = new HashedMap();
        String openid;
        try {
            openid = json.getString("openid");
            map.put("openid", openid);
        } catch(Exception ex) {
            log.error("openid获取异常");
            return null;
        }
        if(StringUtils.isBlank(openid)) {
            log.error("openid获取为空");
            return null;
        }
        try {
            map.put("nickname", json.get("nickname"));
        } catch(Exception ex) {
            map.put("nickname", "");
        }
        try {
            map.put("sex", json.get("sex"));
        } catch(Exception ex) {
            map.put("sex", "");
        }
        try {
            map.put("province", json.get("province"));
        } catch(Exception ex) {
            map.put("province", "");
        }
        try {
            map.put("city", json.get("city"));
        } catch(Exception ex) {
            map.put("city", "");
        }
        try {
            map.put("country", json.get("country"));
        } catch(Exception ex) {
            map.put("nickname", "");
        }
        try {
            map.put("headimgurl", json.get("headimgurl"));
        } catch(Exception ex) {
            map.put("headimgurl", "");
        }
        try {
            map.put("privilege", json.get("privilege"));
        } catch(Exception ex) {
            map.put("privilege", "");
        }
        try {
            map.put("unionid", json.get("unionid"));
        } catch(Exception ex) {
            map.put("unionid", "");
        }
        list.add(map);
        requestJson.put("reginfo", list);
        RequestBody body = RequestBody.create(JSON, requestJson.toString());
        Request req = new Request.Builder().url(accessTokenUrl).post(body).build();
        Response resp = httpClient.newCall(req).execute();
        //
        if(resp.isSuccessful()) {
            responseBody = new JSONObject(resp.body().string());
            log.info(responseBody.toString());
            try {
                return (String) responseBody.get("accesstoken");
            } catch(Exception ex) {
                return null;
            }
        }
        return null;
    }
}
